package com.lantosec.hmrp.modules.workflow.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.lantosec.hmrp.core.exception.AppException;
import com.lantosec.hmrp.core.kit.Result;
import com.lantosec.hmrp.core.kit.ResultEnum;
import com.lantosec.hmrp.core.util.FlowableUtils;
import com.lantosec.hmrp.core.util.UUIDUtils;
import com.lantosec.hmrp.modules.form.entity.FormTempData;
import com.lantosec.hmrp.modules.form.enumeration.ColumnValueTypeEnum;
import com.lantosec.hmrp.modules.form.service.IBindColumnValueService;
import com.lantosec.hmrp.modules.form.service.IFormService;
import com.lantosec.hmrp.modules.form.service.IFormTempDataService;
import com.lantosec.hmrp.modules.form.vo.FormVO;
import com.lantosec.hmrp.modules.sysdata.entity.SysProcessNotify;
import com.lantosec.hmrp.modules.sysdata.entity.SysProcessPublicity;
import com.lantosec.hmrp.modules.sysdata.service.ISysDataProcessService;
import com.lantosec.hmrp.modules.sysdata.service.ISysDataProcessTaskService;
import com.lantosec.hmrp.modules.sysdata.service.ISysProcessNotifyService;
import com.lantosec.hmrp.modules.sysdata.service.ISysProcessPublicityService;
import com.lantosec.hmrp.modules.system.service.ISysUserService;
import com.lantosec.hmrp.modules.system.service.ISysWorkdayService;
import com.lantosec.hmrp.modules.system.vo.UserQueryVO;
import com.lantosec.hmrp.modules.workflow.enumeration.ProcessStatusEnum;
import com.lantosec.hmrp.modules.workflow.enumeration.ProcessVariableEnum;
import com.lantosec.hmrp.modules.workflow.enumeration.TaskOperatorTypeEnum;
import com.lantosec.hmrp.modules.workflow.service.IWorkflowRepositoryService;
import com.lantosec.hmrp.modules.workflow.service.IWorkflowRuntimeService;
import com.lantosec.hmrp.modules.workflow.vo.*;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.FlowNode;
import org.flowable.bpmn.model.SequenceFlow;
import org.flowable.bpmn.model.UserTask;
import org.flowable.common.engine.api.FlowableException;
import org.flowable.engine.IdentityService;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.impl.bpmn.behavior.MultiInstanceActivityBehavior;
import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

@Service
@Primary
@Log4j2
public class WorkflowRuntimeServiceImpl implements IWorkflowRuntimeService {

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private TaskService taskService;

    @Autowired
    private IFormService formService;

    @Autowired
    private IWorkflowRepositoryService workflowRepositoryService;

    @Autowired
    private ISysUserService sysUserService;

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private IdentityService identityService;

    @Autowired
    IBindColumnValueService bindColumnValueService;

    @Autowired
    ISysWorkdayService workdayService;

    @Autowired
    ISysDataProcessService sysDataProcessService;

    @Autowired
    ISysDataProcessTaskService sysDataProcessTaskService;

    @Autowired
    IFormTempDataService formTempDataService;

    @Autowired
    ISysProcessNotifyService sysProcessNotifyService;

    @Autowired
    private ISysProcessPublicityService sysProcessPublicityService;

    /**
     * 通过流程定义的KEY启动流程实例(带变量)
     *
     * @param processInstanceKey 流程定义的KEY
     * @return 返回流程实例ID
     */
    @Override
    public Result<String> startProcessInstanceByKeyHasVariables(String processInstanceKey, Map<String, Object> map) {
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processInstanceKey, map);

        return Result.ok(processInstance.getId());
    }

    private Task startProcessInstance(SaveProcessTaskVO saveVO, String formDataId) {
        JSONObject dataJson = JSON.parseObject(saveVO.getFormData());
        String userId = saveVO.getUserId();
        formDataId = StringUtils.isEmpty(formDataId) ? "" : formDataId;

        Map<String, Object> variables = new HashMap<>();
        variables.put(ProcessVariableEnum.USER_ID.getCode(), userId);
        variables.put(ProcessVariableEnum.BUSINESS_DATA.getCode(), dataJson);
        variables.put(ProcessVariableEnum.BUSINESS_KEY.getCode(), formDataId);
        ProcessInstance processInstance = runtimeService.startProcessInstanceById(saveVO.getProcdefId(), formDataId, variables);
        String processInstanceId = processInstance.getId();

        // 获取当前任务
        Task currentTask = taskService.createTaskQuery().processInstanceId(processInstanceId).singleResult();
        // 指定当前用户流程第一步执行人
        currentTask.setAssignee(userId);
        taskService.setAssignee(currentTask.getId(), userId);
        //保存任务与数据的关系
        sysDataProcessTaskService.saveTask(currentTask, userId, saveVO.getLayoutId(), null, null, null);

        return currentTask;
    }

    @Override
    public FlowTaskVO saveFormData(SaveProcessTaskVO saveVO) {
        //流程操作人，记录在流程历史中
        identityService.setAuthenticatedUserId(saveVO.getUserId());
        Task task;
        if(StringUtils.isNotEmpty(saveVO.getTaskId())) {
            task = taskService.createTaskQuery().taskId(saveVO.getTaskId()).singleResult();
            if (Objects.isNull(task)) {
                throw new AppException("参数taskId错误");
            }
        }else{
            // 如果没有任务Id，则发起新流程
            task = startProcessInstance(saveVO, null);
        }

        FormTempData dbData = formTempDataService.getOne(new QueryWrapper<FormTempData>()
                        .eq(String.valueOf(FormTempData.ColName.user_id), saveVO.getUserId())
                        .eq(String.valueOf(FormTempData.ColName.task_id), saveVO.getTaskId())
        );
        FormTempData formTempData = new FormTempData();
        formTempData.setUserId(saveVO.getUserId());
        formTempData.setProcdefId(saveVO.getProcdefId());
        formTempData.setLayoutId(saveVO.getLayoutId());
        formTempData.setFormData(saveVO.getFormData());
        formTempData.setAuditStatus(saveVO.getAuditStatus());
        formTempData.setComment(saveVO.getComment());

        formTempData.setTaskId(task.getId());

        if (Objects.isNull(dbData)) {
            formTempDataService.save(formTempData);
        } else {
            formTempDataService.update(formTempData, new UpdateWrapper<FormTempData>()
                    .eq(String.valueOf(FormTempData.ColName.user_id), saveVO.getUserId())
                    .eq(String.valueOf(FormTempData.ColName.task_id), saveVO.getTaskId()));
        }

        return new FlowTaskVO(task);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Void> save(SaveProcessTaskVO saveVO) {
        JSONObject dataJson = JSON.parseObject(saveVO.getFormData());

        String userId = saveVO.getUserId();
        // 业务数据Id
        String businessKey = "";

        //流程操作人，记录在流程历史中
        identityService.setAuthenticatedUserId(userId);

        // 没有任务ID，代表新建流程
        if (StringUtils.isBlank(saveVO.getTaskId())) {
            // 保存表单数据
            Result<String> formResult = formService.save(saveVO);
            if (!ResultEnum.SUCCESS.code.equals(formResult.getState())) {
                return Result.fail(formResult.getMessage());
            }
            businessKey = formResult.getData();
            // 获取当前任务
            Task currentTask = startProcessInstance(saveVO, businessKey);

            Map<String, Object> variables = taskService.getVariables(currentTask.getId());
            // 获取当前节点的自定义属性信息
            CustomAttributeVO customAttributeVO = workflowRepositoryService.getCustomAttribute(currentTask.getTaskDefinitionKey(), currentTask.getProcessDefinitionId());
            // 设置表单的任务条件参数
            setConditionVariables(customAttributeVO.getVariableNames(), variables, dataJson);
            // 设置下一个任务会签操作人集合参数的值
            setTaskCountersign(currentTask, variables, userId);

            // 执行第一个节点的任务（如请假流程的申请任务）
            taskService.complete(currentTask.getId(), variables);

        } else {
            String taskId = saveVO.getTaskId();
            Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
            if (Objects.isNull(task)) {
                return Result.fail("该任务不存在");
            }
            task.setAssignee(userId);
            taskService.setAssignee(taskId, userId);

            businessKey = (String) taskService.getVariable(taskId,ProcessVariableEnum.BUSINESS_KEY.getCode());

            // 保存表单数据
            saveVO.setBusinessKey(businessKey);
            Result<String> formResult = formService.save(saveVO);
            if (!ResultEnum.SUCCESS.code.equals(formResult.getState())) {
                return Result.fail(formResult.getMessage());
            }
            if(StringUtils.isEmpty(businessKey)) {
                businessKey = formResult.getData();
                runtimeService.updateBusinessKey(task.getProcessInstanceId(), businessKey);
            }

            // 获取当前节点的自定义属性信息
            CustomAttributeVO customAttributeVO = workflowRepositoryService.getCustomAttribute(task.getTaskDefinitionKey(), task.getProcessDefinitionId());

            JSONObject dbJson = dataJson;
            // 查询数据库的数据记录，放到流程变量里
            Result<FormVO> formVOResult = formService.queryDataByFormId(customAttributeVO.getFormLayoutId(), businessKey);
            if (ResultEnum.SUCCESS.code.equals(formVOResult.getState())) {
                FormVO formVO = formVOResult.getData();
                dbJson = (JSONObject) formVO.getFormData();
            }
            // 任务前事件
            handleBeforeAndAfterEvent(taskId, customAttributeVO.getBeforeEvent(), dbJson);
            // 转发设置
            if (StringUtils.isNotBlank(saveVO.getRelayUser())) {
                List<UserQueryVO> relayUserList = JSONObject.parseArray(saveVO.getRelayUser(), UserQueryVO.class);
                setTaskRelay(task, customAttributeVO.getRelay(), userId, relayUserList, Boolean.FALSE);
            }

            Map<String, Object> variables = taskService.getVariables(taskId);
            variables.put(ProcessVariableEnum.USER_ID.getCode(), userId);
            variables.put(ProcessVariableEnum.BUSINESS_DATA.getCode(), dbJson);
            variables.put(ProcessVariableEnum.BUSINESS_KEY.getCode(), businessKey);
            // 设置表单的任务条件参数
            setConditionVariables(customAttributeVO.getVariableNames(), variables, dbJson);

            // 设置任务的审核参数变量，用于分支的条件判断等
            Integer auditStatus = saveVO.getAuditStatus();
            setTaskAuditVariables(taskId, variables, auditStatus);

            // 设置会签操作人集合参数的值
            setTaskCountersign(task, variables, userId);

            // 完成任务
            taskService.complete(taskId, variables);

            // 任务后事件
            handleBeforeAndAfterEvent(taskId, customAttributeVO.getAfterEvent(), dbJson);

            // 数据回写
            setTaskWriteBack(customAttributeVO.getIsWriteBack(), saveVO.getLayoutId(), businessKey, userId);
            // 流程公示
            setProcessPublicity(task, customAttributeVO.getPublicity(), businessKey, saveVO.getLayoutId(), userId);
            //更新/保存任务与数据的关系
            sysDataProcessTaskService.saveTask(task, userId, saveVO.getLayoutId(), auditStatus, saveVO.getComment(), saveVO.getAutograph());
        }

        // 根据任务的自定义属性指定下一个任务的操作人和过期日期等，改成监听事件类处理（UserTaskCreateListener）
        //setNextTaskByCustomAttribute(processInstanceId, userId);

        return Result.ok();
    }

    /**
     * 任务执行之前/后事件处理，暂时用SQL处理
     *
     * @param taskId     任务Id
     * @param sql        sql语句
     * @param jsonObject 表单数据JSON对象
     */
    private void handleBeforeAndAfterEvent(String taskId, String sql, JSONObject jsonObject) {
        if (StringUtils.isBlank(sql)) {
            return;
        }
        bindColumnValueService.getBindValue(ColumnValueTypeEnum.UPDATE_SQL.getType(), sql, jsonObject);
    }

    /**
     * 设置条件的任务参数
     * @param variableNames 任务参数名配置，保存在流程模型的节点属性上
     * @param variables     流程参数
     * @param dataJson      表单数据JSON对象
     */
    private void setConditionVariables(String variableNames, Map<String, Object> variables, JSONObject dataJson) {
        if (StringUtils.isNotBlank(variableNames)) {
            String[] nameArray = variableNames.split(",");
            for (String item : nameArray) {
                variables.put(item, dataJson.get(item));
            }
        }
        // 根据数据更新条件参数
        for (Map.Entry<String, Object> entry : variables.entrySet()) {
            String key = entry.getKey();
            if (dataJson.containsKey(key)) {
                entry.setValue(dataJson.get(key));
            }
        }
    }

    /**
     * 设置任务节点转发设置（知会/抄送）
     * @param task      任务
     * @param relay     转发配置，保存在流程模型的节点属性上
     * @param userId    用户Id
     * @param userList  指派类型为人工时，用户在前端指定的用户列表
     * @param isDefault 是否默认转发
     */
    @Override
    @Transactional
    public void setTaskRelay(Task task, String relay, String userId, List<UserQueryVO> userList, Boolean isDefault) {
        if (StringUtils.isBlank(relay)) {
            return;
        }
        TaskRelayVO taskRelayVO = JSON.parseObject(relay, TaskRelayVO.class);
        if (Objects.isNull(taskRelayVO)) {
            return;
        }
        if (!Objects.isNull(taskRelayVO.getIsRelay()) && taskRelayVO.getIsRelay() == 0) {
            return;
        }
        if (isDefault) {
            userList = taskRelayVO.getUserList();
        }
        List<String> sqlUserIdList = new ArrayList<>();
        if(StringUtils.isNotEmpty(taskRelayVO.getUserSql())) {
            JSONObject dataJson = (JSONObject) task.getProcessVariables().get(ProcessVariableEnum.BUSINESS_DATA.getCode());
            TaskOperatorVO taskOperatorVO = new TaskOperatorVO();
            taskOperatorVO.setData(taskRelayVO.getUserSql());
            taskOperatorVO.setOptType(TaskOperatorTypeEnum.SQL.getType());
            sqlUserIdList = sysUserService.getOperatorUserIdList(JSON.toJSONString(taskOperatorVO), dataJson, userId);
        }
        if (CollectionUtils.isEmpty(userList) && CollectionUtils.isEmpty(sqlUserIdList)) {
            return;
        }
        // 暂时只取用户Id，如果要根据部门，岗位查询用户，遍历调用 sysUserService.queryUserIdList(item)
        List<String> userIdList = userList.stream().map(UserQueryVO::getUserId).collect(Collectors.toList());
        userIdList.addAll(sqlUserIdList);
        userIdList = userIdList.stream().distinct().collect(Collectors.toList());
        List<SysProcessNotify> list = new ArrayList<>();
        for (String item : userIdList) {
            SysProcessNotify notify = new SysProcessNotify();
            notify.setFormLayoutId(taskRelayVO.getLayoutId());
            notify.setProInsId(task.getProcessInstanceId());
            notify.setTaskId(task.getId());
            notify.setNotifyUserId(item);
            notify.setStartUserId(userId);
            list.add(notify);
        }
        // 保存到流程知会表
        sysProcessNotifyService.saveBatch(list);
    }

    /**
     * 流程公示
     */
    private void setProcessPublicity(Task task, String publicity, String dataId, String layoutId, String userId) {
        if (StringUtils.isBlank(publicity)) {
            return;
        }
        TaskPublicityVO taskPublicityVO = JSON.parseObject(publicity, TaskPublicityVO.class);
        if (Objects.isNull(taskPublicityVO)) {
            return;
        }
        if (!Objects.isNull(taskPublicityVO.getIsPublicity()) && taskPublicityVO.getIsPublicity() == 0) {
            return;
        }
        layoutId = StringUtils.isEmpty(taskPublicityVO.getLayoutId()) ? layoutId : taskPublicityVO.getLayoutId();
        long count = sysProcessPublicityService.getBaseMapper().selectCount(new QueryWrapper<SysProcessPublicity>()
                .eq(SysProcessPublicity.ColName.pro_ins_id.toString(), task.getProcessInstanceId())
                .eq(SysProcessPublicity.ColName.task_id.toString(), task.getId())
        );
        if (count == 0) {
            SysProcessPublicity processPublicity = new SysProcessPublicity();
            processPublicity.setId(UUIDUtils.get());
            processPublicity.setProInsId(task.getProcessInstanceId());
            processPublicity.setTaskId(task.getId());
            processPublicity.setDataId(dataId);
            processPublicity.setLayoutId(layoutId);
            processPublicity.setUserId(userId);
            sysProcessPublicityService.save(processPublicity);
        }
    }

    /**
     * 设置任务的审核参数变量
     * @param taskId        任务Id
     * @param variables     变量集合
     * @param auditStatus   审核状态
     */
    private void setTaskAuditVariables(String taskId, Map<String, Object> variables, Integer auditStatus) {
        // 统计保存审核结果
        if (!Objects.isNull(auditStatus)) {
            // 审核通过数量
            Object agreeCountObject = taskService.getVariable(taskId, ProcessVariableEnum.AGREE_COUNT.getCode());
            int agreeCount = Objects.isNull(agreeCountObject) ? 0 : (Integer) agreeCountObject;
            // 审核不通过数量
            Object disagreeCountObject = taskService.getVariable(taskId, ProcessVariableEnum.DISAGREE_COUNT.getCode());
            int disagreeCount = Objects.isNull(disagreeCountObject) ? 0 : (Integer) disagreeCountObject;
            if (auditStatus > 0) {
                agreeCount++;
            } else {
                disagreeCount++;
            }

            variables.put(ProcessVariableEnum.AUDIT_STATUS.getCode(), auditStatus);
            variables.put(ProcessVariableEnum.AGREE_COUNT.getCode(), agreeCount);
            variables.put(ProcessVariableEnum.DISAGREE_COUNT.getCode(), disagreeCount);
        }
    }

    /**
     * 任务节点会签设置，会签节点才设置
     */
    private void setTaskCountersign(Task task, Map<String, Object> variables, String userId) {
        // 获取下个节点的会签设置
        String nextTaskId = getNextTaskId(task, variables);
        if (StringUtils.isBlank(nextTaskId)) {
            return;
        }
        UserTask nextUserTask = workflowRepositoryService.getUserTask(nextTaskId, task.getProcessDefinitionId());
        // 判断是否是会签节点
        if (!Objects.isNull(nextUserTask) && nextUserTask.getBehavior() instanceof MultiInstanceActivityBehavior) {
            CustomAttributeVO nextAttributeVO = workflowRepositoryService.getCustomAttribute(nextTaskId, task.getProcessDefinitionId());
            // 表单数据
            JSONObject dataJson = (JSONObject) variables.get(ProcessVariableEnum.BUSINESS_DATA.getCode());
            // 设置会签节点操作人集合参数的值
            List<String> nextAssigneeList = sysUserService.getOperatorUserIdList(nextAttributeVO.getOperator(), dataJson, userId);
            variables.put(ProcessVariableEnum.PARTY_USER_ID_LIST.getCode(), nextAssigneeList);
        }
    }

    /**
     * 获取下个任务节点的id，根据当前的流程参数计算线的el表达式，不一定是最终的结果
     * @param task
     * @return
     */
    private String getNextTaskId(Task task, Map<String, Object> variables) {
        FlowNode flowNode = getCurrentFlowNode(task);
        List<SequenceFlow> list = flowNode.getOutgoingFlows();
        if (CollectionUtils.isEmpty(list)) {
            return null;
        }
        // 如果只有一个则直接返回
        if (list.size() == 1) {
            return list.get(0).getTargetRef();
        }

        // 多个通过el表达式匹配获取对应的线
        for (SequenceFlow sequenceFlow : list) {
            // 获取线路的el表达式
            String elCondition = sequenceFlow.getConditionExpression();
            if (StringUtils.isNotBlank(elCondition)) {
                // 计算el表达式，获取对应的节点
                boolean flag = FlowableUtils.isCondition(elCondition, variables);
                if (flag) {
                    return sequenceFlow.getTargetRef();
                }
            }
        }

        return null;
    }

    /**
     * 任务节点回写设置，一般是最后一个节点
     */
    private void setTaskWriteBack(String isWriteBack, String layoutId, String dataId, String userId) {
        if ("1".equals(isWriteBack)) {
            formService.writeBackData(layoutId, dataId, userId);
        }
    }

    /**
     * 指派任务的操作/候选人
     *
     * @param appointVO 指派用户对象
     */
    @Override
    public void appointTask(HandleTaskVO appointVO) {
        if (StringUtils.isBlank(appointVO.getDeptId()) && StringUtils.isBlank(appointVO.getUserId())) {
            throw new FlowableException("参数错误，请指定部门或者人员");
        }
        String taskId = appointVO.getTaskId();
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        if (Objects.isNull(task)) {
            throw new FlowableException("参数错误，任务Id错误");
        }
        identityService.setAuthenticatedUserId(appointVO.getCurrentUserId());

        // 根据查询部门或者人员
        List<String> userIdList = sysUserService.queryUserIdList(appointVO);
        if (CollectionUtils.isNotEmpty(userIdList)) {
            userIdList.forEach(item -> {
                taskService.addCandidateUser(taskId, item);
            });
        }
    }

    /**
     * 转发任务-----把操作人删除，然后添加其他的操作人/候选人
     *
     * @param transmitVO 指派用户对象
     */
    @Override
    public void transmitTask(HandleTaskVO transmitVO) {
        if (StringUtils.isBlank(transmitVO.getDeptId()) && StringUtils.isBlank(transmitVO.getUserId())) {
            throw new FlowableException("参数错误，请指定部门或者人员");
        }
        String taskId = transmitVO.getTaskId();
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        if (Objects.isNull(task)) {
            throw new FlowableException("参数错误，任务Id错误");
        }
        identityService.setAuthenticatedUserId(transmitVO.getCurrentUserId());

        String assignee = task.getAssignee();
        if (StringUtils.isNotBlank(assignee)) {
            taskService.setAssignee(taskId, null);
            //taskService.addCandidateUser(taskId, assignee);
        }
        // 根据查询部门或者人员
        List<String> userIdList = sysUserService.queryUserIdList(transmitVO);
        // 指定操作人/候选人
        if (CollectionUtils.isNotEmpty(userIdList)) {
            if (userIdList.size() == 1) {
                taskService.setAssignee(taskId, userIdList.get(0));
            } else {
                userIdList.forEach(item -> {
                    taskService.addCandidateUser(taskId, item);
                });
            }
        }

    }

    /**
     * 作废流程
     */
    @Override
    public Result<Void> deleteProcessInstance(DeleteProcessInstanceVO deleteVO) {
        String processInstanceId = deleteVO.getProcessInstanceId();
        List<Task> list = taskService.createTaskQuery().processInstanceId(processInstanceId).list();
        if (CollectionUtils.isEmpty(list)) {
            throw new FlowableException("参数错误，流程Id错误");
        }
        identityService.setAuthenticatedUserId(deleteVO.getUserId());

        runtimeService.deleteProcessInstance(processInstanceId, deleteVO.getReason());

        //更新流程实例与数据的关系表,流程结束时间
        sysDataProcessService.updateProcess(processInstanceId, list.get(0).getId(), list.get(0).getTaskDefinitionKey(), list.get(0).getName(),
                new Date(), ProcessStatusEnum.CLOSE.getType(), null);
        list.forEach(task -> {
            sysDataProcessTaskService.saveTask(task, deleteVO.getUserId(),"", 0, deleteVO.getReason(), null);
        });
        return Result.ok();
    }

    /**
     * 将此任务的所有权转移给其他用户。不检查标识组件是否知道用户。
     *
     * @param taskId   任务的taskId，不能为空
     * @param assignee 要用作分配者的用户的用户标识
     */
    @Override
    public void setTransfers(String taskId, String assignee) {
        taskService.setOwner(taskId, assignee);
    }

    /**
     * 设置流程变量(绑定任务)用Map形式
     *
     * @param taskId 任务ID
     * @param map    流程量
     */
    @Override
    public void setVariablesByTaskIdAsMap(String taskId, Map<String, Object> map) {
        taskService.setVariablesLocal(taskId, map);
    }

    /**
     * 设置流程变量(不绑定任务)
     *
     * @param taskId 任务ID
     * @param key
     * @param value
     */
    @Override
    public void setVariablesByTaskId(String taskId, String key, String value) {
        taskService.setVariable(taskId, key, value);
    }

    /**
     * 移除流程变量(从正在运行中)
     *
     * @param processInstanceId 流程实例ID
     * @param key
     */
    @Override
    public void removeVariablesByProcessInstanceId(String processInstanceId, String key) {
        runtimeService.removeVariable(processInstanceId, key);
    }

    /**
     * 回退任务
     *
     * @param backVO 回退流程对象
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void backTask(BackProcessInstanceVO backVO) {
        String processInstanceId = backVO.getProcessInstanceId();
        String userId = backVO.getUserId();

        List<Task> list = taskService.createTaskQuery().processInstanceId(processInstanceId).list();
        if (CollectionUtils.isEmpty(list)) {
            throw new FlowableException("参数错误，没有查询到任务");
        }
        identityService.setAuthenticatedUserId(backVO.getUserId());

        list.forEach(task -> {
            // 保存任务信息
            task.setAssignee(userId);
            taskService.setAssignee(task.getId(), userId);
        });
        // 上一个节点
        String distFlowElementId = getPrevActivityId(list.get(0));

        List<Task> tasks = taskService.createTaskQuery().processInstanceId(processInstanceId).list();
        List<String> currentActivityIds = new ArrayList<>();
        tasks.forEach(t -> currentActivityIds.add(t.getTaskDefinitionKey()));

        // 保存表单数据
        /*Result<String> formResult = formService.save(new SaveProcessTaskVO(backVO.getLayoutId(), backVO.getFormData()));
        if (!ResultEnum.SUCCESS.code.equals(formResult.getState())) {
            throw new FlowableException(formResult.getMessage());
        }
        String formDataId = formResult.getData();*/

        // 执行驳回操作
        runtimeService.createChangeActivityStateBuilder()
                .processInstanceId(processInstanceId)
                .moveActivityIdsToSingleActivityId(currentActivityIds, distFlowElementId)
                .changeState();

        //保存任务与数据的关系
        list.forEach(task -> {
            sysDataProcessTaskService.saveTask(task, userId, backVO.getLayoutId(), 0, backVO.getComment(), null);
        });
    }

    /***
     * 获取当前任务的上一个节点
     * @param task  当前任务
     * @return
     */
    private String getPrevActivityId(Task task) {
        FlowNode flowNode = getCurrentFlowNode(task);
        SequenceFlow sequenceFlow = flowNode.getIncomingFlows().get(0);
        // 获取上一个节点的activityId
        return sequenceFlow.getSourceRef();
    }

    private FlowNode getCurrentFlowNode(Task task){
        ExecutionEntity execution = (ExecutionEntity) runtimeService.createExecutionQuery().executionId(task.getExecutionId()).singleResult();
        // 获取当前节点的activityId,即xml中每个标签的ID
        String currentActivityId = execution.getCurrentActivityId();
        BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId());
        return (FlowNode) bpmnModel.getFlowElement(currentActivityId);
    }

}
